package gold.digger;

import java.util.*;

/**
 * Created by fanzhenyu02 on 2020/6/27.
 * common problem solver template.
 */
public class LC273 {
    public long startExecuteTime = System.currentTimeMillis();

    class Solution {
        private final String[] THOUSAND = {"", "Thousand", "Million", "Billion"};
        private final String[] LESS_THAN_TWENTY = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
        private final String[] HUNDRED = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};

        public String numberToWords(int num) {
            if (num == 0) return "Zero";

            StringBuilder sb = new StringBuilder();
            int index = 0;
            while (num > 0) {
                if (num % 1000 != 0) {
                    StringBuilder tmp = new StringBuilder();
                    helper(num % 1000, tmp);
                    sb.insert(0, tmp.append(THOUSAND[index]).append(" "));
                }
                index++;
                num /= 1000;
            }
            return sb.toString().trim();
        }

        private void helper(int num, StringBuilder tmp) {
            if (num == 0) return;
            if (num < 20) {
                tmp.append(LESS_THAN_TWENTY[num]).append(" ");
            } else if (num < 100) {
                tmp.append(HUNDRED[num / 10]).append(" ");
                helper(num % 10, tmp);
            } else {
                tmp.append(LESS_THAN_TWENTY[num / 100]).append(" Hundred").append(" ");
                helper(num % 100, tmp);
            }
        }
    }


    /**
     * 数值	短级差系统命名	长级差系统命名
     * 103 =	thousand	thousand
     * 106 =	million	million
     * 109 =	billion	milliard
     * 1012 =	trillion	billion
     * 1015 =	quadrillion	billiard
     * 1018 =	quintillion	trillion
     * 1021 =	sextillion	trilliard
     * 1024 =	septillion	quadrillion
     * 1027 =	octillion	quadrilliard
     * 1030 =	nonillion	quintillion
     * 1033 =	decillion	quintilliard
     * 1036 =	undecillion	sextillion
     * 1039 =	duodecillion	sextilliard
     * 1042 =	tredecillion	septillion
     * 1045 =	quattuordecillion	septilliard
     * 1048 =	quindecillion	octillion
     * 1051 =	sexdecillion	octilliard
     * 1054 =	septendecillion	nonillion
     * 1057 =	octodecillion	nonilliard
     * 1060 =	novemdecillion	decillion
     * 1063 =	vigintillion	decilliard
     */
    static class Solution_Over_Too_Complex {
        public static Map<Integer, String> bitMap = new HashMap<>();
        public static Map<Integer, String> numOneMap = new HashMap<>();
        public static Map<Integer, String> numTenMap = new HashMap<>();

        static {
            numOneMap.put(0, "Zero");
            numOneMap.put(1, "One");
            numOneMap.put(2, "Two");
            numOneMap.put(3, "Three");
            numOneMap.put(4, "Four");
            numOneMap.put(5, "Five");
            numOneMap.put(6, "Six");
            numOneMap.put(7, "Seven");
            numOneMap.put(8, "Eight");
            numOneMap.put(9, "Nine");


            numTenMap.put(0, "Zero");
            numTenMap.put(1, "One");
            numTenMap.put(2, "Twenty");
            numTenMap.put(3, "Thirty");
            numTenMap.put(4, "Forty");
            numTenMap.put(5, "Fifty");
            numTenMap.put(6, "Sixty");
            numTenMap.put(7, "Seventy");
            numTenMap.put(8, "Eighty");
            numTenMap.put(9, "Ninety");


            numTenMap.put(10, "Ten");
            numTenMap.put(11, "Eleven");
            numTenMap.put(12, "Twelve");
            numTenMap.put(13, "Thirteen");
            numTenMap.put(14, "Fourteen");
            numTenMap.put(15, "Fifteen");
            numTenMap.put(16, "Sixteen");
            numTenMap.put(17, "Seventeen");
            numTenMap.put(18, "Eighteen");
            numTenMap.put(19, "Nineteen");


            int i = 0;
            bitMap.put(i++, "");
            bitMap.put(i++, "Thousand");
            bitMap.put(i++, "Million");
            bitMap.put(i++, "Billion");
            bitMap.put(i++, "Trillio");
            bitMap.put(i++, "Quadrillion");
            bitMap.put(i++, "Quintillion");
            bitMap.put(i++, "Sextillion");
            bitMap.put(i++, "septillion");
            bitMap.put(i++, "Octillion");
            bitMap.put(i++, "Nonillion");
            bitMap.put(i++, "decillion");
        }

        public String numberToWords(int num) {
            int bitCount = 0;
            String numStr = String.valueOf(num);
            StringBuilder res = new StringBuilder();
            int curPos = numStr.length() - 1;
            for (; curPos >= 2; curPos -= 3, bitCount++) {
                int hundredBit = numStr.charAt(curPos - 2) - '0';
                int tenBit = numStr.charAt(curPos - 1) - '0';
                int oneBit = numStr.charAt(curPos) - '0';
                String curRes = (curPos > 2 ? " " : "") + numOneMap.get(hundredBit) + " " + "Hundred" + " ";
                if (tenBit == 0) {
                    curRes += numOneMap.get(oneBit) + (bitMap.get(bitCount).length() <= 0 ? "" : " ") + bitMap.get(bitCount);
                } else if (tenBit == 1 || oneBit == 0) {
                    curRes += numTenMap.get((oneBit == 0) ? tenBit : tenBit * 10 + oneBit) + (bitMap.get(bitCount).length() <= 0 ? "" : " ") + bitMap.get(bitCount);
                } else {
                    curRes += numTenMap.get(tenBit) + " " + numOneMap.get(oneBit) + (bitMap.get(bitCount).length() <= 0 ? "" : " ") + bitMap.get(bitCount);
                }

                res.insert(0, curRes);
            }

            if (curPos == 1) {
                int tenBit = numStr.charAt(curPos - 1) - '0';
                int oneBit = numStr.charAt(curPos) - '0';

                String curRes = "";
                if (tenBit == 1 || oneBit == 0) {
                    curRes += numTenMap.get((oneBit == 0) ? tenBit : tenBit * 10 + oneBit) + (bitMap.get(bitCount).length() <= 0 ? "" : " ") + bitMap.get(bitCount);
                } else {
                    curRes += numTenMap.get(tenBit) + " " + numOneMap.get(oneBit) + " " + bitMap.get(bitCount);
                }
                res.insert(0, curRes);
            } else if (curPos == 0) {
                int oneBit = numStr.charAt(curPos) - '0';
                String curRes = numOneMap.get(oneBit) + " " + bitMap.get(bitCount);
                res.insert(0, curRes);
            }

            return res.toString().trim();
        }
    }

    public void run() {
        Solution solution = new Solution();
        System.out.println(solution.numberToWords(120));
    }

    public static void main(String[] args) throws Exception {
        LC273 an = new LC273();
        an.run();

        System.out.println("\ncurrent solution total execute time: " + (System.currentTimeMillis() - an.startExecuteTime) + " ms.");
    }
}
